import os
import random

from PIL import Image
import numpy

from _Qfunc.pct_print import PctShow  # 打印格式获取
from _Qfunc.path_func import Path  # 路径类获取
from _Qfunc.same_func import path_name_type  # 路径-名称-类型拆分
from _Qfunc.same_func import get_methods  # 类内方法获取
from _Qfunc.same_func import rand  # 随机返回结果
from _JugMachine.body import JugMethod


def rand_color():
    """随机颜色返回"""
    return random.randint(0, 255)

def render_unit(object:list, reference:list, inherit:float) -> None:
    for i in range(len(object)):
        object[i] = int((object[i] * inherit + reference[i] * (1 - inherit)))


class IM:

    def __init__(self, resp=None, card_p=None, funclist=None, parmlist=None):
        self.w, self.h = 0, 0

        self.path = ''  # 路径
        self.type = ''  # 文件类型
        self.name = ''  # 文件名

        self.p = Path(1)  # 项目的绝对路径信息
        self.p.back()
        if resp is not None:
            self.p.to(resp)   # floop位置

        self.fp = Path(1)
        self.fp.back()
        if card_p is not None:  # 色卡位置
            self.fp.to(card_p)

        self.funclist = funclist
        self.parmlist = parmlist

    # # 基础功能|basic function ############################
    def new_canvas(self, im):
        """新建画布：作为空白数组，复制等量空间"""
        return im * 0

    def update_status(self, image, name):
        """更新记录的图像状态信息，不包括像素数据"""
        self.w, self.h = image.size
        tmp = path_name_type(name)
        self.path = tmp[0]
        self.name = tmp[1]
        self.type = tmp[2]

    def open_image(self, name, kind=None):
        """打开图像：转码，并记录标签内容"""
        image = Image.open(name)
        self.update_status(image, name)
        if kind is not None:
            image = image.convert(kind)
        return numpy.asarray(image)

    def save_image(self, name, im, func='floop'):
        """图像存储"""
        image = Image.fromarray(numpy.uint8(im))
        if func == 'floop':
            path = self.p.to(self.name, goto=False)
        elif func == 'color_card':
            path = self.fp.now
        image.save(path + name)

    def name_end(self) -> str:
        """获取文件名尾部标签"""
        tag = str(random.randint(100000, 999999))
        name = tag + self.type
        return name

    def get_jug(self, num):
        """获取滤波器"""
        return JugMethod(num, self.funclist, self.parmlist)

    def show_histogram(self, im):
        """直方图显示"""
        from matplotlib import pyplot as plt
        x = self.open_image(im, 'L')
        plt.hist(x, alpha=0.8)
        plt.show()

    # # 滤波器方法|filter method ############################
    block_status = [(-1, -1), (0, -1), (1, -1),
                    (-1, 0), (0, 0), (1, 0),
                    (-1, 1), (0, 1), (1, 1)]

    def floop(self, image, num=0, kind=None, func=None):
        """
        # 滤波器 批量方法使用

        :param image: 图像路径
        :param num: 执行次数，为0时执行全部
        :param kind: 写出图片色彩类型
        :param func: 展示方法
        :return:
        """
        from _ImgFactory.func_s import Show  # 导入方法内容
        f = Show()  # 实例化
        funcs = get_methods(f)  # 获取可用方法
        jug = self.get_jug(num)  # 构造器获取
        num = len(jug.funclist) if num == 0 else num
        funclist = rand(funcs, num) if func is None else [func] * num  # 方法确认


        tmp = []
        img = self.open_image(image, kind='L')  # 打开图像，以灰度形式，作为判断依据
        img_op = self.open_image(image, kind=kind)  # 打开图像，并获取kind形式矩阵，作为结果处理依据
        for i in range(num):
            tmp.append(self.new_canvas(img_op))  # 画布空间获取

        tag = f'floop[{num}] - {self.name} '
        p = PctShow(self.h, tag=tag, fix=-1)  # 打印,执行循环遍历过程
        for i in range(1, self.h - 1):
            p.update(i)
            for j in range(1, self.w - 1):

                block = []
                for k in self.block_status:  # 渲染器所需结果获取
                    block.append(img[i + k[0]][j + k[1]])

                results = jug.just_doit(block)  # 解析结果获取

                for k in range(num):  # 对图像装填
                    tmp[k][i][j] = getattr(f, funclist[k])(results[k], img_op[i][j])

        func = jug.funclist
        parm = jug.parmlist
        for i in range(num):  # 保存结果
            name = tag + f'_{func[i]}_{parm[i]}_{funclist[i]} - ' + self.name_end()
            self.save_image(name, tmp[i])
        p.endl(num)

    # # 色彩灰度比值|color gray scale ############################
    def color2gray(self, image, scale=8):
        """
        # 捕获目标图像的色相分栏(无意义)

        :param image: 需要分析的图像，但是读取结果 完 全 主 观 ！
        :param scale: 色卡比例，默认系数乘256
        :return: 产出一张色卡图像，与相关txt文档
        """
        tmp = [[0, 0, 0] for i in range(256)]
        img = self.open_image(image, 'L')
        img_rgb = self.open_image(image, 'RGB')

        tag = f'color2gray - {self.name} '
        p = PctShow(self.h, tag=tag)  # 打印,执行循环遍历过程
        for i in range(self.h):
            p.update(i)
            for j in range(self.w):
                if list(tmp[img[i][j]]) == [0, 0, 0]:
                    tmp[img[i][j]] = list(img_rgb[i][j])
                elif sum(tmp[img[i][j]])/3 < 150:
                    render_unit(tmp[img[i][j]], list(img_rgb[i][j]), 0.35)
                elif (max(tmp[img[i][j]])-min(tmp[img[i][j]])) < 128:
                    render_unit(tmp[img[i][j]], list(img_rgb[i][j]), 0.75)

        name = self.fp.now + tag + '.txt'
        with open(name, 'w') as ff:
            ff.write(str(tmp))
        self.gray_check(name, scale)

    def gray2color(self, image, txt):
        """
        # 对图像按照色卡特征重新着色

        :param image: 图像，会被转为灰色图像重新着色
        :param txt: 读取图像色卡，或者特征文件都可以
        :return: 产出一张重着色图像
        """
        tmp = self.charge_list(txt)
        img = self.open_image(image, 'L')
        img_rgb = self.open_image(image, 'RGB')
        tmp_rgb = self.new_canvas(img_rgb)
        txt = txt[txt.rfind('/') + 1:]

        tag = f'gray2color - {self.name} - {txt[13:].strip(".txt.png")} '
        p = PctShow(self.h, tag=tag)  # 打印,执行循环遍历过程
        for i in range(self.h):
            p.update(i)
            for j in range(self.w):
                tmp_rgb[i][j] = tmp[img[i][j]]

        end = self.name_end()
        self.save_image(tag + end, tmp_rgb)

    def charge_list(self, txt) -> list:
        """读取色卡或特征文本"""
        try:  # 读入文本
            with open(txt, 'r') as ff:  # 读取特征，并转换为list
                tmp = ff.read()
                tmp = tmp[2:-2].split('], [')
            for i in range(len(tmp)):
                t = tmp[i].split(',')
                tmp[i] = t
            return tmp
        except:  # 读入图像
            tmp = [[0, 0, 0] for i in range(256)]
            tmp_img = self.open_image(txt, 'RGB')
            k = int(self.w / 256)

            for i in range(256):
                tmp[i] = tmp_img[0][i * k]

            return tmp

    def gray_check(self, txt, scale=8):
        """将特征文档转为色卡显示"""
        tmp = self.charge_list(txt)
        tmp_img = [[[0, 0, 0] for i in range(256*scale)] for i in range(64)]
        ppos = txt.rfind('/') + 1
        txt = txt[ppos:] if ppos != 0 else txt

        tag = f'gray2color - {txt[13:].strip(".txt")} '
        for i in range(64):
            for j in range(256*scale):
                k = int(j / 8)
                tmp_img[i][j] = tmp[k]

        end = '.png'
        self.save_image(tag + end, tmp_img, 'color_card')

    def rand_card(self, group=1):
        """随机色卡获取"""
        tmp = [[rand_color() for i in range(3)] for i in range(256)]
        n = int(len(tmp) / group)
        tmp_color = rand(tmp, n + 1, repeat=False)  # 根据分组重新着色
        for i in range(n):
            for j in range(group):
                for k in range(3):
                    tmp[j + i * group][k] = int(tmp_color[i][k] * ((256 - j * 8) / 256))

        tmp_img = [[[0, 0, 0] for i in range(2048)] for i in range(64)]

        tag = f'gray2color - {random.randint(10000, 99999)} '
        p = PctShow(64, tag=tag)  # 打印,执行循环遍历过程
        for i in range(64):
            p.update(i)
            for j in range(2048):
                k = int(j / 8)
                tmp_img[i][j] = tmp[k]

        end = '.png'
        self.save_image(tag + end, tmp_img, 'color_card')
    ########################################



